using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using SeataNet.Core.Common;
using SeataNet.Core.Context;
using SeataNet.Core.Exceptions;
using SeataNet.Core.AT;
using SeataNet.Core.TCC;
using SeataNet.Core.Saga;
using SeataNet.Core.XA;
using SeataNet.Core.RPC;
using SeataNet.Core.Protocol;
using SeataNet.Core.Model;
using System.Net;

namespace SeataNet.Core.Transaction
{
    /// <summary>
    /// 默认事务管理器实现
    ///
    /// 职责：
    /// 1. 管理全局事务的完整生命周期（开始、提交、回滚、查询状态）
    /// 2. 与TC（事务协调器）通信，发送全局事务操作请求
    /// 3. 管理事务上下文，包括全局事务和分支事务的绑定/解绑
    /// 4. 生成全局事务ID和分支事务ID
    /// 5. 协调分支事务的注册和状态上报
    ///
    /// 工作流程：
    /// 1. 开始阶段：
    ///    - 生成XID（全局事务ID）
    ///    - 向TC发送GlobalBeginRequest
    ///    - 绑定全局事务上下文到当前线程
    ///
    /// 2. 执行阶段：
    ///    - 各分支向TC注册（RegisterBranchAsync）
    ///    - 各分支执行本地业务逻辑
    ///    - 各分支上报执行状态（ReportBranchStatusAsync）
    ///
    /// 3. 提交阶段：
    ///    - 向TC发送GlobalCommitRequest
    ///    - TC通知所有分支提交
    ///    - 解绑全局事务上下文
    ///
    /// 4. 回滚阶段：
    ///    - 向TC发送GlobalRollbackRequest
    ///    - TC通知所有分支回滚
    ///    - 解绑全局事务上下文
    ///
    /// 线程安全：
    /// 使用RootContext（ThreadLocal）存储事务上下文，支持多线程并发。
    /// </summary>
    public class DefaultTransactionManager : ITransactionManager
    {
        private readonly ILogger<DefaultTransactionManager> _logger;
        private readonly IOptionsMonitor<SeataNetConfiguration> _configuration;
        private readonly IRpcClient _rpcClient;
        private readonly ITransactionIdGenerator _transactionIdGenerator;
        private readonly ITransactionContextManager _contextManager;
        private readonly IResourceManager _resourceManager;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="logger">日志记录器</param>
        /// <param name="configuration">Seata配置</param>
        /// <param name="rpcClient">RPC客户端，用于与TC通信</param>
        /// <param name="transactionIdGenerator">事务ID生成器</param>
        /// <param name="contextManager">事务上下文管理器</param>
        /// <param name="resourceManager">资源管理器，管理分支事务</param>
        public DefaultTransactionManager(
            ILogger<DefaultTransactionManager> logger,
            IOptionsMonitor<SeataNetConfiguration> configuration,
            IRpcClient rpcClient,
            ITransactionIdGenerator transactionIdGenerator,
            ITransactionContextManager contextManager,
            IResourceManager resourceManager)
        {
            _logger = logger;
            _configuration = configuration;
            _rpcClient = rpcClient;
            _transactionIdGenerator = transactionIdGenerator;
            _contextManager = contextManager;
            _resourceManager = resourceManager;
        }

        /// <summary>
        /// 开始全局事务
        ///
        /// 这是全局事务的入口方法，负责生成XID并向TC注册全局事务。
        ///
        /// 执行流程：
        /// 1. 生成唯一的全局事务ID（XID）
        /// 2. 设置默认超时时间和事务名称（如果未指定）
        /// 3. 构造GlobalBeginRequest请求
        /// 4. 通过RPC发送请求到TC（事务协调器）
        /// 5. 如果成功，绑定事务上下文到当前线程并返回XID
        /// 6. 如果失败，记录日志并抛出异常
        ///
        /// 调用时机：
        /// - 在业务逻辑开始前调用
        /// - 通常由@GlobalTransactional注解自动触发
        ///
        /// 注意事项：
        /// - 该方法会阻塞等待TC响应
        /// - XID将被存储在RootContext（ThreadLocal）中
        /// - 超时时间决定了整个全局事务的有效期限
        /// </summary>
        /// <param name="transactionName">事务名称，用于标识业务场景，默认为Transaction_时间戳</param>
        /// <param name="timeout">超时时间（毫秒），默认60000ms（60秒），超时后TC会自动回滚</param>
        /// <returns>全局事务ID（XID），格式为：IP:时间戳:随机数</returns>
        /// <exception cref="TransactionException">开始事务失败时抛出，通常是TC不可达或拒绝请求</exception>
        public string Begin(string? transactionName = null, int timeout = 60000)
        {
            var xid = _transactionIdGenerator.GenerateTransactionId();
            var config = _configuration.CurrentValue;

            // 设置默认超时时间
            if (timeout <= 0)
            {
                timeout = config.DefaultTimeout;
            }

            // 设置默认事务名称
            if (string.IsNullOrEmpty(transactionName))
            {
                transactionName = $"Transaction_{DateTime.Now:yyyyMMddHHmmss}";
            }

            // 创建全局事务请求
            var request = new GlobalBeginRequest
            {
                TransactionName = transactionName,
                Timeout = timeout
            };

            // 发送请求到TC
            var response = _rpcClient.SendAsync<GlobalBeginRequest, GlobalBeginResponse>(request).Result;

            if (response.ResultCode == ResultCode.Success)
            {
                _logger.LogInformation("Global transaction begun, XID: {Xid}, TransactionName: {TransactionName}",
                    response.Xid, transactionName);

                // 绑定事务上下文
                _contextManager.BindGlobalTransaction(response.Xid, transactionName, timeout);

                return response.Xid;
            }
            else
            {
                _logger.LogError("Failed to begin global transaction, TransactionName: {TransactionName}, Error: {Error}",
                    transactionName, response.ErrorMessage);
                throw new TransactionException($"Failed to begin global transaction: {response.ErrorMessage}");
            }
        }

        /// <summary>
        /// 提交全局事务
        ///
        /// 这是全局事务的提交方法，通知TC提交所有分支事务。
        ///
        /// 执行流程：
        /// 1. 验证XID不能为空
        /// 2. 构造GlobalCommitRequest请求
        /// 3. 通过RPC发送提交请求到TC
        /// 4. TC收到请求后异步通知所有分支执行提交操作
        /// 5. 无论成功与否，都解绑当前线程的事务上下文
        ///
        /// 提交过程（由TC协调）：
        /// - 第一阶段：各分支已完成本地事务提交（但undo_log还在）
        /// - 第二阶段（此方法触发）：TC通知各分支删除undo_log并释放锁
        ///
        /// 调用时机：
        /// - 业务逻辑正常执行完成后
        /// - 通常由@GlobalTransactional注解自动触发
        ///
        /// 注意事项：
        /// - 该方法会阻塞等待TC响应
        /// - 提交是异步的，TC会后台协调各分支提交
        /// - 即使提交失败，事务上下文也会被解绑
        /// - 提交失败通常是由于网络问题或TC不可达
        /// </summary>
        /// <param name="xid">全局事务ID，必须是有效的XID</param>
        /// <returns>提交响应，包含结果码和错误信息（如果有）</returns>
        /// <exception cref="ArgumentException">XID为空时抛出</exception>
        public GlobalCommitResponse Commit(string xid)
        {
            if (string.IsNullOrEmpty(xid))
            {
                throw new ArgumentException("XID cannot be null or empty", nameof(xid));
            }

            var request = new GlobalCommitRequest
            {
                Xid = xid
            };

            var response = _rpcClient.SendAsync<GlobalCommitRequest, GlobalCommitResponse>(request).Result;

            if (response.ResultCode == ResultCode.Success)
            {
                _logger.LogInformation("Global transaction committed, XID: {Xid}", xid);
            }
            else
            {
                _logger.LogError("Failed to commit global transaction, XID: {Xid}, Error: {Error}",
                    xid, response.ErrorMessage);
            }

            // 解绑事务上下文
            _contextManager.UnbindGlobalTransaction();

            return response;
        }

        /// <summary>
        /// 回滚全局事务
        ///
        /// 这是全局事务的回滚方法，通知TC回滚所有分支事务。
        ///
        /// 执行流程：
        /// 1. 验证XID不能为空
        /// 2. 构造GlobalRollbackRequest请求
        /// 3. 通过RPC发送回滚请求到TC
        /// 4. TC收到请求后异步通知所有分支执行回滚操作
        /// 5. 无论成功与否，都解绑当前线程的事务上下文
        ///
        /// 回滚过程（由TC协调）：
        /// - AT模式：TC通知各分支查询undo_log，生成反向SQL并执行，恢复数据到事务前状态
        /// - TCC模式：TC通知各分支调用Cancel方法，执行补偿操作
        /// - Saga模式：TC通知各分支执行补偿事务，逆序执行补偿操作
        /// - XA模式：TC通知各分支执行XA ROLLBACK
        ///
        /// 调用时机：
        /// - 业务逻辑执行异常时
        /// - 手动调用GlobalTransaction.rollback()时
        /// - 事务超时时由TC自动触发
        ///
        /// 注意事项：
        /// - 该方法会阻塞等待TC响应
        /// - 回滚是异步的，TC会后台协调各分支回滚
        /// - 即使回滚失败，事务上下文也会被解绑
        /// - 回滚失败会记录日志，需要人工介入处理
        /// </summary>
        /// <param name="xid">全局事务ID，必须是有效的XID</param>
        /// <returns>回滚响应，包含结果码和错误信息（如果有）</returns>
        /// <exception cref="ArgumentException">XID为空时抛出</exception>
        public GlobalRollbackResponse Rollback(string xid)
        {
            if (string.IsNullOrEmpty(xid))
            {
                throw new ArgumentException("XID cannot be null or empty", nameof(xid));
            }

            var request = new GlobalRollbackRequest
            {
                Xid = xid
            };

            var response = _rpcClient.SendAsync<GlobalRollbackRequest, GlobalRollbackResponse>(request).Result;

            if (response.ResultCode == ResultCode.Success)
            {
                _logger.LogInformation("Global transaction rolled back, XID: {Xid}", xid);
            }
            else
            {
                _logger.LogError("Failed to rollback global transaction, XID: {Xid}, Error: {Error}",
                    xid, response.ErrorMessage);
            }

            // 解绑事务上下文
            _contextManager.UnbindGlobalTransaction();

            return response;
        }

        /// <summary>
        /// 查询全局事务状态
        ///
        /// 向TC查询指定XID的全局事务当前状态。
        ///
        /// 执行流程：
        /// 1. 验证XID不能为空
        /// 2. 构造GlobalStatusRequest请求
        /// 3. 通过RPC发送状态查询请求到TC
        /// 4. TC返回该全局事务的当前状态
        ///
        /// 事务状态说明：
        /// - Begin: 事务已开始，正在执行中
        /// - Committing: 事务提交中，正在通知各分支提交
        /// - Committed: 事务已提交完成
        /// - Rollbacking: 事务回滚中，正在通知各分支回滚
        /// - RolledBack: 事务已回滚完成
        /// - Failed: 事务执行失败
        /// - Unknown: 未知状态（XID不存在或已被清理）
        ///
        /// 使用场景：
        /// - 事务状态监控
        /// - 事务恢复判断
        /// - 分布式跟踪和诊断
        /// </summary>
        /// <param name="xid">全局事务ID</param>
        /// <returns>全局事务状态枚举值</returns>
        /// <exception cref="ArgumentException">XID为空时抛出</exception>
        /// <exception cref="TransactionException">查询失败时抛出，通常是TC不可达</exception>
        public GlobalStatus GetStatus(string xid)
        {
            if (string.IsNullOrEmpty(xid))
            {
                throw new ArgumentException("XID cannot be null or empty", nameof(xid));
            }

            var request = new GlobalStatusRequest
            {
                Xid = xid
            };

            var response = _rpcClient.SendAsync<GlobalStatusRequest, GlobalStatusResponse>(request).Result;

            if (response.ResultCode == ResultCode.Success)
            {
                return response.GlobalStatus;
            }
            else
            {
                _logger.LogError("Failed to get global transaction status, XID: {Xid}, Error: {Error}",
                    xid, response.ErrorMessage);
                throw new TransactionException($"Failed to get global transaction status: {response.ErrorMessage}");
            }
        }

        /// <summary>
        /// 获取全局事务报告
        ///
        /// 查询全局事务的详细信息和统计报告。
        ///
        /// 执行流程：
        /// 1. 验证XID不能为空
        /// 2. 构造GlobalReportRequest请求，包含应用ID和事务服务组
        /// 3. 通过RPC发送报告请求到TC
        /// 4. TC返回该全局事务的详细报告
        ///
        /// 报告内容包括：
        /// - 全局事务状态
        /// - 所有分支事务信息
        /// - 开始时间、结束时间
        /// - 超时配置
        /// - 执行统计（分支数、成功数、失败数等）
        ///
        /// 使用场景：
        /// - 事务监控仪表板
        /// - 事务问题诊断
        /// - 性能分析和优化
        /// - 审计和日志
        /// </summary>
        /// <param name="xid">全局事务ID</param>
        /// <returns>全局事务报告，包含详细信息和统计数据</returns>
        /// <exception cref="ArgumentException">XID为空时抛出</exception>
        /// <exception cref="TransactionException">查询失败时抛出</exception>
        public GlobalReportResponse GetGlobalReport(string xid)
        {
            if (string.IsNullOrEmpty(xid))
            {
                throw new ArgumentException("XID cannot be null or empty", nameof(xid));
            }

            var request = new GlobalReportRequest
            {
                Xid = xid,
                ApplicationId = _configuration.CurrentValue.ApplicationId,
                TransactionServiceGroup = _configuration.CurrentValue.TransactionServiceGroup
            };

            var response = _rpcClient.SendAsync<GlobalReportRequest, GlobalReportResponse>(request).Result;

            if (response.ResultCode == ResultCode.Success)
            {
                return response;
            }
            else
            {
                _logger.LogError("Failed to get global transaction report, XID: {Xid}, Error: {Error}",
                    xid, response.ErrorMessage);
                throw new TransactionException($"Failed to get global transaction report: {response.ErrorMessage}");
            }
        }

        // ========== 异步方法实现 ==========
        // 以下方法提供异步API，适用于async/await编程模式

        /// <summary>
        /// 异步开始全局事务
        ///
        /// 异步版本的Begin()方法，使用Task.Run包装同步方法。
        ///
        /// 注意：虽然此方法是异步的，但底层的Begin()方法仍然是同步阻塞的。
        /// 这里的异步主要是为了提供统一的async/await接口。
        /// </summary>
        /// <param name="timeout">超时时间（毫秒），默认60000ms</param>
        /// <param name="name">事务名称，默认为Transaction_时间戳</param>
        /// <returns>异步任务，返回全局事务ID（XID）</returns>
        public async Task<string> BeginAsync(int timeout = 60000, string? name = null)
        {
            return await Task.Run(() => Begin(name, timeout));
        }

        /// <summary>
        /// 异步提交全局事务
        ///
        /// 异步版本的Commit()方法。
        ///
        /// 执行流程：
        /// 1. 调用同步Commit()方法
        /// 2. 检查响应结果码
        /// 3. 返回是否提交成功
        ///
        /// 注意：返回true表示TC已接受提交请求，但不代表所有分支都已提交完成。
        /// </summary>
        /// <param name="xid">全局事务ID</param>
        /// <returns>异步任务，返回提交是否成功（true/false）</returns>
        public async Task<bool> CommitAsync(string xid)
        {
            var result = await Task.Run(() => Commit(xid));
            return result.ResultCode == ResultCode.Success;
        }

        /// <summary>
        /// 异步回滚全局事务
        ///
        /// 异步版本的Rollback()方法。
        ///
        /// 执行流程：
        /// 1. 调用同步Rollback()方法
        /// 2. 检查响应结果码
        /// 3. 返回是否回滚成功
        ///
        /// 注意：返回true表示TC已接受回滚请求，但不代表所有分支都已回滚完成。
        /// </summary>
        /// <param name="xid">全局事务ID</param>
        /// <returns>异步任务，返回回滚是否成功（true/false）</returns>
        public async Task<bool> RollbackAsync(string xid)
        {
            var result = await Task.Run(() => Rollback(xid));
            return result.ResultCode == ResultCode.Success;
        }

        /// <summary>
        /// 异步查询全局事务状态
        ///
        /// 异步版本的GetStatus()方法。
        ///
        /// 返回值说明：
        /// - 返回int类型的状态码，可转换为GlobalStatus枚举
        /// - 各状态码对应的值请参考GlobalStatus枚举定义
        /// </summary>
        /// <param name="xid">全局事务ID</param>
        /// <returns>异步任务，返回事务状态的整数值</returns>
        public async Task<int> GetStatusAsync(string xid)
        {
            var status = await Task.Run(() => GetStatus(xid));
            return (int)status;
        }

        /// <summary>
        /// 异步获取全局事务上下文
        ///
        /// 查询全局事务的状态并构造事务上下文对象。
        ///
        /// 执行流程：
        /// 1. 调用GetStatus()查询事务状态
        /// 2. 如果状态为Unknown，返回null（事务不存在）
        /// 3. 否则构造GlobalTransactionContext对象并返回
        ///
        /// 上下文包含：
        /// - XID: 全局事务ID
        /// - Status: 事务状态
        /// - ApplicationId: 应用ID
        /// - TransactionServiceGroup: 事务服务组
        /// - Timeout: 超时时间
        /// - BeginTime: 开始时间
        ///
        /// 使用场景：
        /// - 事务恢复时需要获取完整上下文
        /// - 事务监控需要显示详细信息
        /// </summary>
        /// <param name="xid">全局事务ID</param>
        /// <returns>异步任务，返回全局事务上下文对象，如果事务不存在则返回null</returns>
        public async Task<GlobalTransactionContext?> GetGlobalTransactionAsync(string xid)
        {
            // 获取全局事务状态
            var status = await Task.Run(() => GetStatus(xid));

            if (status == GlobalStatus.Unknown)
            {
                return null;
            }

            // 创建全局事务上下文
            var context = new GlobalTransactionContext
            {
                Xid = xid,
                Status = (int)status,
                ApplicationId = _configuration.CurrentValue.ApplicationId,
                TransactionServiceGroup = _configuration.CurrentValue.TransactionServiceGroup,
                Timeout = _configuration.CurrentValue.DefaultTimeout,
                BeginTime = DateTime.UtcNow
            };

            return context;
        }

        /// <summary>
        /// 异步注册分支事务
        ///
        /// 在全局事务下注册一个分支事务，分支事务代表对某个资源（通常是数据库）的操作。
        ///
        /// 执行流程：
        /// 1. 记录日志：记录正在注册的分支信息
        /// 2. 调用资源管理器的BranchRegisterAsync方法
        /// 3. 向TC发送分支注册请求
        /// 4. TC分配分支ID并返回
        /// 5. 记录成功日志
        ///
        /// 注册时机：
        /// - 在执行SQL之前注册分支
        /// - 确保XID已存在（全局事务已开始）
        /// - 在数据库连接上下文中调用
        ///
        /// lockKey说明：
        /// - AT模式：格式为"表名:主键值"，如"user_table:1001"
        /// - 用于行锁的并发控制
        /// - 多个行锁用分号分隔，如"user_table:1001;user_table:1002"
        ///
        /// 异常处理：
        /// - 注册失败会记录错误日志并向上抛出异常
        /// - 通常是由于TC不可达或锁冲突导致
        /// </summary>
        /// <param name="xid">全局事务ID</param>
        /// <param name="resourceId">资源ID，通常是数据库连接串或数据源名称</param>
        /// <param name="lockKey">锁键，用于行锁的并发控制</param>
        /// <returns>异步任务，返回分支事务ID</returns>
        /// <exception cref="Exception">注册失败时抛出</exception>
        public async Task<long> RegisterBranchAsync(string xid, string resourceId, string lockKey)
        {
            try
            {
                _logger.LogDebug("Registering branch: XID={Xid}, ResourceId={ResourceId}, LockKey={LockKey}",
                    xid, resourceId, lockKey);

                // 使用资源管理器注册分支
                var branchId = await _resourceManager.BranchRegisterAsync("AT", xid, resourceId, lockKey, null);

                _logger.LogInformation("Branch registered successfully: XID={Xid}, BranchId={BranchId}",
                    xid, branchId);

                return branchId;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to register branch: XID={Xid}", xid);
                throw;
            }
        }

        /// <summary>
        /// 异步上报分支事务状态
        ///
        /// 分支在执行本地事务后，向TC上报执行结果。
        ///
        /// 执行流程：
        /// 1. 记录日志：记录正在上报的分支状态
        /// 2. 调用资源管理器的BranchReportAsync方法
        /// 3. 向TC发送分支状态报告
        /// 4. TC记录分支状态
        /// 5. 记录成功日志
        ///
        /// 状态说明：
        /// - PhaseOneDone: 第一阶段完成（本地事务已提交）
        /// - PhaseOneFailed: 第一阶段失败（本地事务执行失败）
        /// - PhaseTwoCommitted: 第二阶段提交完成
        /// - PhaseTwoRollbacked: 第二阶段回滚完成
        ///
        /// 上报时机：
        /// - 本地事务执行完成后（成功或失败都要上报）
        /// - 第二阶段操作完成后（提交或回滚完成）
        ///
        /// 注意事项：
        /// - 上报失败会记录错误日志并向上抛出异常
        /// - TC根据所有分支的状态决定是否进行全局提交或回滚
        /// </summary>
        /// <param name="xid">全局事务ID</param>
        /// <param name="branchId">分支事务ID，由RegisterBranchAsync返回</param>
        /// <param name="status">分支事务状态</param>
        /// <returns>异步任务</returns>
        /// <exception cref="Exception">上报失败时抛出</exception>
        public async Task ReportBranchStatusAsync(string xid, long branchId, BranchStatus status)
        {
            try
            {
                _logger.LogDebug("Reporting branch status: XID={Xid}, BranchId={BranchId}, Status={Status}",
                    xid, branchId, status);

                // 使用资源管理器上报分支状态
                await _resourceManager.BranchReportAsync(xid, branchId, (int)status, null);

                _logger.LogInformation("Branch status reported successfully: XID={Xid}, BranchId={BranchId}",
                    xid, branchId);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to report branch status: XID={Xid}, BranchId={BranchId}",
                    xid, branchId);
                throw;
            }
        }

        /// <summary>
        /// 异步获取分支事务状态
        ///
        /// 查询指定分支的当前状态。
        ///
        /// 注意：
        /// - 这是一个简化实现，当前总是返回Unknown状态
        /// - 实际生产环境中应该向TC查询真实的分支状态
        /// - 需要实现RPC调用来获取TC中存储的分支状态信息
        ///
        /// TODO: 实现真正的分支状态查询
        /// 应该调用类似BranchStatusRequest的RPC请求到TC，查询真实状态。
        ///
        /// 使用场景：
        /// - 事务恢复时需要确认分支状态
        /// - 事务监控需要查看分支执行情况
        /// - 分支异常排查
        /// </summary>
        /// <param name="xid">全局事务ID</param>
        /// <param name="branchId">分支事务ID</param>
        /// <returns>异步任务，返回分支事务状态（当前总是返回Unknown）</returns>
        public async Task<BranchStatus> GetBranchStatusAsync(string xid, long branchId)
        {
            try
            {
                _logger.LogDebug("Getting branch status: XID={Xid}, BranchId={BranchId}", xid, branchId);

                // 这里简化实现,实际应该从TC查询分支状态
                // 暂时返回Unknown,实际实现需要调用RPC客户端查询
                await Task.CompletedTask;

                _logger.LogDebug("Branch status retrieved: XID={Xid}, BranchId={BranchId}", xid, branchId);

                return BranchStatus.Unknown;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Failed to get branch status: XID={Xid}, BranchId={BranchId}",
                    xid, branchId);
                throw;
            }
        }
    }

    /// <summary>
    /// 事务上下文管理器接口
    ///
    /// 负责管理全局事务和分支事务的上下文信息。
    ///
    /// 职责：
    /// 1. 将XID绑定到当前线程（使用ThreadLocal）
    /// 2. 从当前线程获取XID
    /// 3. 在事务完成后解绑XID
    /// 4. 管理分支事务的上下文信息
    ///
    /// 设计理念：
    /// - 使用RootContext（ThreadLocal）实现线程隔离
    /// - 支持嵌套事务上下文
    /// - 自动传播事务上下文到子线程（如需要）
    ///
    /// 使用场景：
    /// - 在事务开始时绑定XID
    /// - 在SQL执行前获取当前XID
    /// - 在事务结束时清理上下文
    /// </summary>
    public interface ITransactionContextManager
    {
        /// <summary>
        /// 绑定全局事务上下文
        ///
        /// 将全局事务信息绑定到当前线程，使得后续操作可以获取到XID。
        /// </summary>
        /// <param name="xid">全局事务ID</param>
        /// <param name="transactionName">事务名称，用于日志和监控</param>
        /// <param name="timeout">超时时间（毫秒）</param>
        void BindGlobalTransaction(string xid, string transactionName, int timeout);

        /// <summary>
        /// 解绑全局事务上下文
        ///
        /// 从当前线程中移除事务上下文，通常在事务提交或回滚后调用。
        /// </summary>
        void UnbindGlobalTransaction();

        /// <summary>
        /// 获取当前全局事务ID
        ///
        /// 从当前线程的上下文中获取XID。
        /// </summary>
        /// <returns>全局事务ID，如果不在事务中则返回null</returns>
        string? GetCurrentXid();

        /// <summary>
        /// 检查是否在全局事务中
        ///
        /// 判断当前线程是否已绑定全局事务上下文。
        /// </summary>
        /// <returns>true表示在全局事务中，false表示不在</returns>
        bool InGlobalTransaction();

        /// <summary>
        /// 绑定分支事务上下文
        ///
        /// 将分支事务信息绑定到当前线程，包括分支类型、资源ID、锁键等。
        /// </summary>
        /// <param name="branchType">分支类型（AT/TCC/Saga/XA）</param>
        /// <param name="resourceId">资源ID</param>
        /// <param name="lockKey">锁键</param>
        void BindBranchTransaction(string branchType, string resourceId, string lockKey);

        /// <summary>
        /// 解绑分支事务上下文
        ///
        /// 从当前线程中移除分支事务上下文。
        /// </summary>
        void UnbindBranchTransaction();

        /// <summary>
        /// 获取当前分支事务上下文
        ///
        /// 获取当前线程绑定的分支事务信息。
        /// </summary>
        /// <returns>分支事务上下文，如果没有则返回null</returns>
        BranchTransactionContext? GetCurrentBranchContext();
    }

    /// <summary>
    /// 默认事务上下文管理器实现
    ///
    /// 职责：
    /// 1. 实现ITransactionContextManager接口
    /// 2. 使用RootContext（基于AsyncLocal的ThreadLocal）存储事务上下文
    /// 3. 提供线程安全的上下文绑定和解绑操作
    ///
    /// 实现细节：
    /// - RootContext.Bind(xid)：将XID存储到当前线程
    /// - RootContext.Unbind()：清除当前线程的XID
    /// - RootContext.Xid：获取当前线程的XID
    /// - RootContext.InGlobalTransaction：检查当前线程是否在事务中
    ///
    /// 线程安全：
    /// - 使用AsyncLocal实现，天然支持async/await
    /// - 每个线程有独立的事务上下文
    /// - 子线程不会自动继承父线程的事务上下文（除非显式传播）
    ///
    /// 使用示例：
    /// ```csharp
    /// // 开始事务时绑定
    /// _contextManager.BindGlobalTransaction(xid, "MyTransaction", 60000);
    ///
    /// // 业务代码中获取
    /// var currentXid = _contextManager.GetCurrentXid();
    ///
    /// // 事务结束时解绑
    /// _contextManager.UnbindGlobalTransaction();
    /// ```
    /// </summary>
    public class DefaultTransactionContextManager : ITransactionContextManager
    {
        private readonly ILogger<DefaultTransactionContextManager> _logger;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="logger">日志记录器</param>
        public DefaultTransactionContextManager(ILogger<DefaultTransactionContextManager> logger)
        {
            _logger = logger;
        }

        /// <summary>
        /// 绑定全局事务上下文
        ///
        /// 执行流程：
        /// 1. 将XID绑定到RootContext（当前线程）
        /// 2. 设置分支类型为AT模式（默认）
        /// 3. 记录绑定日志
        ///
        /// 注意事项：
        /// - 多次调用会覆盖之前的绑定
        /// - 绑定后，当前线程及其async延续都能获取到XID
        /// - 不会自动传播到新创建的线程
        /// </summary>
        /// <param name="xid">全局事务ID</param>
        /// <param name="transactionName">事务名称</param>
        /// <param name="timeout">超时时间</param>
        public void BindGlobalTransaction(string xid, string transactionName, int timeout)
        {
            RootContext.Bind(xid);
            RootContext.BindBranchType(Common.TransactionConstants.BRANCH_TYPE_AT);
            _logger.LogDebug("Global transaction context bound, XID: {Xid}, TransactionName: {TransactionName}",
                xid, transactionName);
        }

        /// <summary>
        /// 解绑全局事务上下文
        ///
        /// 执行流程：
        /// 1. 获取当前XID用于日志记录
        /// 2. 从RootContext解绑XID
        /// 3. 解绑分支类型
        /// 4. 记录解绑日志
        ///
        /// 注意事项：
        /// - 即使未绑定，调用此方法也是安全的（无副作用）
        /// - 通常在事务提交或回滚后调用
        /// - 解绑后GetCurrentXid()将返回null
        /// </summary>
        public void UnbindGlobalTransaction()
        {
            var xid = RootContext.Xid;
            RootContext.Unbind();
            RootContext.UnbindBranchType();
            _logger.LogDebug("Global transaction context unbound, XID: {Xid}", xid);
        }

        /// <summary>
        /// 获取当前全局事务ID
        ///
        /// 从RootContext中读取当前线程绑定的XID。
        /// </summary>
        /// <returns>XID，如果当前线程未绑定则返回null</returns>
        public string? GetCurrentXid()
        {
            return RootContext.Xid;
        }

        /// <summary>
        /// 检查是否在全局事务中
        ///
        /// 判断当前线程是否已绑定全局事务。
        /// </summary>
        /// <returns>true表示在事务中，false表示不在</returns>
        public bool InGlobalTransaction()
        {
            return RootContext.InGlobalTransaction;
        }

        /// <summary>
        /// 绑定分支事务上下文
        ///
        /// 执行流程：
        /// 1. 绑定分支类型到RootContext
        /// 2. 记录绑定日志
        ///
        /// 注意：
        /// - 分支类型包括：AT、TCC、Saga、XA
        /// - 分支上下文会影响资源管理器的行为
        /// </summary>
        /// <param name="branchType">分支类型</param>
        /// <param name="resourceId">资源ID</param>
        /// <param name="lockKey">锁键</param>
        public void BindBranchTransaction(string branchType, string resourceId, string lockKey)
        {
            RootContext.BindBranchType(branchType);
            _logger.LogDebug("Branch transaction context bound, BranchType: {BranchType}, ResourceId: {ResourceId}",
                branchType, resourceId);
        }

        /// <summary>
        /// 解绑分支事务上下文
        ///
        /// 从RootContext中移除分支类型信息。
        /// </summary>
        public void UnbindBranchTransaction()
        {
            RootContext.UnbindBranchType();
            _logger.LogDebug("Branch transaction context unbound");
        }

        /// <summary>
        /// 获取当前分支事务上下文
        ///
        /// 执行流程：
        /// 1. 从RootContext读取XID和分支类型
        /// 2. 如果任一为空，返回null
        /// 3. 否则构造BranchTransactionContext并返回
        ///
        /// 使用场景：
        /// - 资源管理器需要获取当前分支信息
        /// - SQL拦截器需要判断分支类型
        /// </summary>
        /// <returns>分支事务上下文，如果未绑定则返回null</returns>
        public BranchTransactionContext? GetCurrentBranchContext()
        {
            var xid = RootContext.Xid;
            var branchType = RootContext.BranchType;

            if (string.IsNullOrEmpty(xid) || string.IsNullOrEmpty(branchType))
            {
                return null;
            }

            return new BranchTransactionContext
            {
                Xid = xid,
                BranchType = branchType
            };
        }
    }

    /// <summary>
    /// 事务ID生成器接口
    ///
    /// 负责生成全局事务ID和分支事务ID。
    ///
    /// 职责：
    /// 1. 生成全局唯一的事务ID（XID）
    /// 2. 生成分支事务ID（在应用内唯一即可）
    ///
    /// XID格式要求：
    /// - 全局唯一：跨所有应用实例唯一
    /// - 可追溯：能够从XID中识别来源（IP、时间等）
    /// - 紧凑：便于存储和传输
    ///
    /// 设计考虑：
    /// - 性能：生成速度要快，避免成为瓶颈
    /// - 冲突：尽量避免ID冲突
    /// - 可读性：便于日志查看和问题排查
    /// </summary>
    public interface ITransactionIdGenerator
    {
        /// <summary>
        /// 生成全局事务ID
        ///
        /// XID必须全局唯一，通常包含以下信息：
        /// - IP地址：标识生成XID的机器
        /// - 时间戳：标识生成时间
        /// - 随机数或序列号：避免同一毫秒内的冲突
        /// </summary>
        /// <returns>全局唯一的事务ID</returns>
        string GenerateTransactionId();

        /// <summary>
        /// 生成分支事务ID
        ///
        /// 分支ID在当前应用实例内唯一即可。
        /// 通常使用递增序列号。
        /// </summary>
        /// <returns>分支事务ID</returns>
        long GenerateBranchId();
    }

    /// <summary>
    /// 默认事务ID生成器实现
    ///
    /// 职责：
    /// 1. 生成格式为"IP:时间戳:随机数"的全局事务ID
    /// 2. 使用Interlocked.Increment生成递增的分支ID
    ///
    /// XID生成算法：
    /// - 格式：{LocalIP}:{UnixTimestamp}:{RandomNumber}
    /// - 示例：192.168.1.100:1703123456789:5678
    /// - IP部分：标识生成XID的机器，便于追踪来源
    /// - 时间戳：Unix毫秒时间戳，标识事务开始时间
    /// - 随机数：4位数字（1000-9999），避免同一毫秒内冲突
    ///
    /// 分支ID生成算法：
    /// - 使用Interlocked.Increment确保线程安全的递增
    /// - 从1开始递增，在应用实例内唯一
    /// - 应用重启后会重置为1
    ///
    /// 线程安全：
    /// - GenerateTransactionId()：每次都创建新的Random实例和时间戳，线程安全
    /// - GenerateBranchId()：使用Interlocked.Increment保证原子性操作，线程安全
    ///
    /// 注意事项：
    /// - IP获取失败时使用127.0.0.1作为默认值
    /// - 如果机器有多个网卡，只使用第一个IPv4地址
    /// - 分支ID溢出后会从负数继续（理论上不太可能发生）
    /// </summary>
    public class DefaultTransactionIdGenerator : ITransactionIdGenerator
    {
        private readonly ILogger<DefaultTransactionIdGenerator> _logger;
        private readonly string _applicationId;
        // 分支ID计数器，使用Interlocked保证线程安全
        private long _branchId = 0;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="logger">日志记录器</param>
        /// <param name="configuration">Seata配置，用于获取应用ID</param>
        public DefaultTransactionIdGenerator(
            ILogger<DefaultTransactionIdGenerator> logger,
            IOptionsMonitor<SeataNetConfiguration> configuration)
        {
            _logger = logger;
            _applicationId = configuration.CurrentValue.ApplicationId;
        }

        /// <summary>
        /// 生成全局事务ID
        ///
        /// 执行流程：
        /// 1. 获取本机IP地址（首个IPv4地址）
        /// 2. 获取当前Unix毫秒时间戳
        /// 3. 生成4位随机数（1000-9999）
        /// 4. 组合为"{IP}:{Timestamp}:{Random}"格式
        /// 5. 记录日志并返回
        ///
        /// XID示例：
        /// - 192.168.1.100:1703123456789:5678
        /// - 10.0.0.50:1703123456790:1234
        /// - 127.0.0.1:1703123456791:9876（IP获取失败时）
        ///
        /// 冲突概率：
        /// - 同一毫秒内在同一机器上生成相同随机数的概率：1/9000
        /// - 通过IP和时间戳组合，实际冲突概率极低
        /// </summary>
        /// <returns>全局唯一的事务ID</returns>
        public string GenerateTransactionId()
        {
            var ip = GetLocalIpAddress();
            var timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
            var random = new Random().Next(1000, 9999);

            var xid = $"{ip}:{timestamp}:{random}";
            _logger.LogDebug("Generated transaction ID: {Xid}", xid);

            return xid;
        }

        /// <summary>
        /// 生成分支事务ID
        ///
        /// 使用Interlocked.Increment实现线程安全的递增序列。
        ///
        /// 特点：
        /// - 从1开始递增
        /// - 每次调用返回递增后的值
        /// - 线程安全，无需额外加锁
        /// - 应用重启后重置为1
        ///
        /// 示例序列：
        /// - 第1次调用：返回1
        /// - 第2次调用：返回2
        /// - 第3次调用：返回3
        /// - ...依此类推
        /// </summary>
        /// <returns>分支事务ID</returns>
        public long GenerateBranchId()
        {
            return Interlocked.Increment(ref _branchId);
        }

        /// <summary>
        /// 获取本机IP地址
        ///
        /// 执行流程：
        /// 1. 通过Dns.GetHostEntry获取本机所有IP地址
        /// 2. 遍历地址列表，查找第一个IPv4地址
        /// 3. 如果找到，返回该IP地址字符串
        /// 4. 如果未找到或发生异常，返回"127.0.0.1"
        ///
        /// 注意事项：
        /// - 只返回IPv4地址，跳过IPv6地址
        /// - 如果有多个网卡，只返回第一个IPv4地址
        /// - 可能返回局域网IP（如192.168.x.x）或公网IP
        /// - 在Docker容器中可能返回容器内部IP
        ///
        /// 异常处理：
        /// - DNS查询失败：记录警告日志，返回127.0.0.1
        /// - 网络配置问题：记录警告日志，返回127.0.0.1
        /// </summary>
        /// <returns>本机IPv4地址字符串，获取失败时返回"127.0.0.1"</returns>
        private string GetLocalIpAddress()
        {
            try
            {
                var host = Dns.GetHostEntry(Dns.GetHostName());
                foreach (var ip in host.AddressList)
                {
                    if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
                    {
                        return ip.ToString();
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "Failed to get local IP address");
            }

            return "127.0.0.1";
        }
    }

    /// <summary>
    /// 分支事务上下文
    ///
    /// 存储分支事务的基本信息，用于在线程上下文中传递分支相关数据。
    ///
    /// 用途：
    /// 1. 保存当前线程执行的分支事务信息
    /// 2. 提供给资源管理器和SQL拦截器使用
    /// 3. 在RPC调用间传播事务上下文
    ///
    /// 使用场景：
    /// - SQL执行前获取分支上下文，判断事务模式
    /// - 分支注册时构造完整的上下文信息
    /// - 跨服务调用时传播分支信息
    ///
    /// 注意：
    /// - 这是一个数据传输对象（DTO），不包含业务逻辑
    /// - 通常通过ITransactionContextManager.GetCurrentBranchContext()获取
    /// </summary>
    public class BranchTransactionContext
    {
        /// <summary>
        /// 全局事务ID
        ///
        /// 标识该分支所属的全局事务。
        /// 格式：IP:时间戳:随机数，如"192.168.1.100:1703123456789:5678"
        /// </summary>
        public string Xid { get; set; } = string.Empty;

        /// <summary>
        /// 分支类型
        ///
        /// 标识该分支使用的事务模式。
        ///
        /// 可选值：
        /// - "AT"：自动事务模式，基于undo_log实现自动回滚
        /// - "TCC"：Try-Confirm-Cancel模式，需要手动实现三个阶段方法
        /// - "Saga"：Saga模式，基于补偿事务实现最终一致性
        /// - "XA"：XA两阶段提交模式，依赖数据库XA协议支持
        /// </summary>
        public string BranchType { get; set; } = string.Empty;

        /// <summary>
        /// 分支ID
        ///
        /// TC分配的分支事务唯一标识。
        /// 由DefaultTransactionManager.RegisterBranchAsync()调用时由TC返回。
        /// 在应用实例内递增，重启后重置。
        /// </summary>
        public long BranchId { get; set; }

        /// <summary>
        /// 资源ID
        ///
        /// 标识该分支操作的资源（通常是数据库）。
        ///
        /// 格式示例：
        /// - JDBC: "jdbc:mysql://localhost:3306/seata_order"
        /// - Data Source Name: "OrderDB"
        /// - Connection String: "Server=localhost;Database=seata_order;..."
        ///
        /// 用途：
        /// - 资源管理器根据ResourceId路由到对应的资源处理器
        /// - TC使用ResourceId管理分支的锁信息
        /// - 事务恢复时定位资源执行补偿操作
        /// </summary>
        public string ResourceId { get; set; } = string.Empty;

        /// <summary>
        /// 锁键
        ///
        /// 用于行锁的并发控制，标识该分支锁定的数据行。
        ///
        /// 格式：表名:主键值
        /// 示例：
        /// - 单行锁："user_table:1001"
        /// - 多行锁："user_table:1001;user_table:1002;order_table:5001"
        /// - 表锁："user_table" （AT模式下很少使用）
        ///
        /// 作用：
        /// - TC根据LockKey检测并发冲突
        /// - 避免多个全局事务同时修改同一行数据
        /// - 第一阶段获取锁，第二阶段释放锁
        ///
        /// 注意：
        /// - TCC和Saga模式通常不使用LockKey
        /// - AT模式下LockKey由SQL解析器自动生成
        /// - 多行锁用分号";"分隔
        /// </summary>
        public string LockKey { get; set; } = string.Empty;
    }

}